Crate bevy_reflect

source ·
Expand description

Bevy Reflect

This crate enables you to dynamically interact with Rust types:

  • Derive the Reflect traits
  • Interact with fields using their names (for named structs) or indices (for tuple structs)
  • “Patch” your types with new values
  • Look up nested fields using “path strings”
  • Iterate over struct fields
  • Automatically serialize and deserialize via Serde (without explicit serde impls)
  • Trait “reflection”

Features

Derive the Reflect traits

// this will automatically implement the Reflect trait and the Struct trait (because the type is a struct)
#[derive(Reflect)]
struct Foo {
    a: u32,
    b: Bar,
    c: Vec<i32>,
    d: Vec<Baz>,
}

// this will automatically implement the Reflect trait and the TupleStruct trait (because the type is a tuple struct)
#[derive(Reflect)]
struct Bar(String);

#[derive(Reflect, FromReflect)]
struct Baz {
    value: f32,
}

// We will use this value to illustrate `bevy_reflect` features
let mut foo = Foo {
    a: 1,
    b: Bar("hello".to_string()),
    c: vec![1, 2],
    d: vec![Baz { value: 3.14 }],
};

Interact with fields using their names

assert_eq!(*foo.get_field::<u32>("a").unwrap(), 1);

*foo.get_field_mut::<u32>("a").unwrap() = 2;

assert_eq!(foo.a, 2);

“Patch” your types with new values

let mut dynamic_struct = DynamicStruct::default();
dynamic_struct.insert("a", 42u32);
dynamic_struct.insert("c", vec![3, 4, 5]);

foo.apply(&dynamic_struct);

assert_eq!(foo.a, 42);
assert_eq!(foo.c, vec![3, 4, 5]);

Look up nested fields using “path strings”

let value = *foo.get_path::<f32>("d[0].value").unwrap();
assert_eq!(value, 3.14);

Iterate over struct fields

for (i, value: &Reflect) in foo.iter_fields().enumerate() {
    let field_name = foo.name_at(i).unwrap();
    if let Some(value) = value.downcast_ref::<u32>() {
        println!("{} is a u32 with the value: {}", field_name, *value);
    }
}

Automatically serialize and deserialize via Serde (without explicit serde impls)

let mut registry = TypeRegistry::default();
registry.register::<u32>();
registry.register::<i32>();
registry.register::<f32>();
registry.register::<String>();
registry.register::<Bar>();
registry.register::<Baz>();

let serializer = ReflectSerializer::new(&foo, &registry);
let serialized = ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();

let mut deserializer = ron::de::Deserializer::from_str(&serialized).unwrap();
let reflect_deserializer = ReflectDeserializer::new(&registry);
let value = reflect_deserializer.deserialize(&mut deserializer).unwrap();
let dynamic_struct = value.take::<DynamicStruct>().unwrap();

assert!(foo.reflect_partial_eq(&dynamic_struct).unwrap());

Trait “reflection”

Call a trait on a given &dyn Reflect reference without knowing the underlying type!

#[derive(Reflect)]
#[reflect(DoThing)]
struct MyType {
    value: String,
}

impl DoThing for MyType {
    fn do_thing(&self) -> String {
        format!("{} World!", self.value)
    }
}

#[reflect_trait]
pub trait DoThing {
    fn do_thing(&self) -> String;
}

// First, lets box our type as a Box<dyn Reflect>
let reflect_value: Box<dyn Reflect> = Box::new(MyType {
    value: "Hello".to_string(),
});

// This means we no longer have direct access to MyType or its methods. We can only call Reflect methods on reflect_value.
// What if we want to call `do_thing` on our type? We could downcast using reflect_value.downcast_ref::<MyType>(), but what if we
// don't know the type at compile time?

// Normally in rust we would be out of luck at this point. Lets use our new reflection powers to do something cool!
let mut type_registry = TypeRegistry::default();
type_registry.register::<MyType>();

// The #[reflect] attribute we put on our DoThing trait generated a new `ReflectDoThing` struct, which implements TypeData.
// This was added to MyType's TypeRegistration.
let reflect_do_thing = type_registry
    .get_type_data::<ReflectDoThing>(reflect_value.type_id())
    .unwrap();

// We can use this generated type to convert our `&dyn Reflect` reference to a `&dyn DoThing` reference
let my_trait: &dyn DoThing = reflect_do_thing.get(&*reflect_value).unwrap();

// Which means we can now call do_thing(). Magic!
println!("{}", my_trait.do_thing());

// This works because the #[reflect(MyTrait)] we put on MyType informed the Reflect derive to insert a new instance
// of ReflectDoThing into MyType's registration. The instance knows how to cast &dyn Reflect to &dyn MyType, because it
// knows that &dyn Reflect should first be downcasted to &MyType, which can then be safely casted to &dyn MyType

Why make this?

The whole point of Rust is static safety! Why build something that makes it easy to throw it all away?

  • Some problems are inherently dynamic (scripting, some types of serialization / deserialization)
  • Sometimes the dynamic way is easier
  • Sometimes the dynamic way puts less burden on your users to derive a bunch of traits (this was a big motivator for the Bevy project)

Re-exports

pub use erased_serde;

Modules

Helpers for working with Bevy reflection.

Macros

A replacement for #[derive(Reflect)] to be used with foreign types which the definitions of cannot be altered.

Structs

A container for compile-time array info.
An iterator over an Array.
A fixed-size list of reflected values.
A dynamic representation of an enum.
A container for compile-time info related to Bevy’s dynamic types, including primitives.
A list of reflected values.
An ordered mapping between reflected values.
A struct type which allows fields to be added at runtime.
A tuple which allows fields to be added at runtime.
A tuple struct which allows fields to be added at runtime.
A container for compile-time enum info, used by TypeInfo.
An iterator over the field values of a struct.
A container for compile-time list info.
A container for compile-time map info.
An iterator over the key-value pairs of a Map.
The named field of a reflected struct.
A struct used to deserialize reflected instances of a type.
Reflect values are commonly used in situations where the actual types of values are not known at runtime. In such situations you might have access to a *const () pointer that you know implements Reflect, but have no way of turning it into a &dyn Reflect.
A Hasher for hashing an arbitrary stream of bytes.
A struct used to serialize reflected instances of a type.
A container for compile-time struct info.
Type info for struct variants.
An iterator over the field values of a tuple.
A container for compile-time tuple info.
An iterator over the field values of a tuple struct.
A container for compile-time tuple struct info.
Type info for tuple variants.
A record of data about a type.
A registry of reflected types.
A synchronized wrapper around a TypeRegistry.
Type info for unit variants.
The unnamed field of a reflected tuple or tuple struct.
A Universally Unique Identifier (UUID).
A container for compile-time info related to general value types, including primitives.
An iterator over the fields in the current enum variant.

Enums

A dynamic representation of an enum variant.
A mutable enumeration of “kinds” of reflected type.
An owned enumeration of “kinds” of reflected type.
An error returned from a failed path string query.
An immutable enumeration of “kinds” of reflected type.
Compile-time type information for various reflected types.
A container for compile-time enum variant info.
Describes the form of an enum variant.

Traits

A static-sized array of Reflect items.
A trait representing a reflected enum.
A trait for types which can be constructed from a reflected type.
Trait used to generate TypeData for trait reflection.
A convenience trait which combines fetching and downcasting of struct fields.
A trait which allows nested values to be retrieved with path strings.
A convenience trait which combines fetching and downcasting of tuple fields.
A convenience trait which combines fetching and downcasting of tuple struct fields.
A trait which allows a type to generate its TypeRegistration.
An ordered, mutable list of Reflect items. This corresponds to types like std::vec::Vec.
An ordered mapping between Reflect values.
A reflected Rust type.
A reflected Rust regular struct type.
A reflected Rust tuple.
A reflected Rust tuple struct.
A trait for types generated by the #[reflect_trait] attribute macro.
A trait for types with a statically associated UUID.
A trait for types with an associated UUID.
A static accessor to compile-time type information.

Functions

Applies the reflected array data to the given array.
The default debug formatter for Array types.
Returns the u64 hash of the given array.
Compares two arrays (one concrete and one reflected) to see if they are equal.
The default debug formatter for Enum types.
Returns the u64 hash of the given enum.
Compares an Enum with a Reflect value.
Applies the elements of b to the corresponding elements of a.
The default debug formatter for List types.
Compares a List with a Reflect value.
Applies the elements of reflected map b to the corresponding elements of map a.
The default debug formatter for Map types.
Compares a Map with a Reflect value.
The default debug formatter for Struct types.
Compares a Struct with a Reflect value.
Applies the elements of b to the corresponding elements of a.
The default debug formatter for Tuple types.
Compares a Tuple with a Reflect value.
The default debug formatter for TupleStruct types.

Attribute Macros

Derive Macros

Derives the FromReflect trait.